
"""
    用户
"""

import jwt
from django.contrib.auth.hashers import make_password
from django.contrib.auth.hashers import check_password
from django.db.models import Q
from rest_framework_jwt.settings import api_settings
from ROOT.settings import SECRET_KEY
from utils.json_response import JsonResponse
from utils.model_view_set import CustomModelViewSet
from rest_framework.views import APIView
from rest_framework.decorators import action
from rest_framework import status
from users.models import Menu, UserProfileModel
from users.serialiaers import menu, user
from audit.views.landing import landing
from operator import itemgetter
from audit.views import operation

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


# Create your views here.

# data = json.loads(request.body.decode('utf-8'))


class UserAuthView(APIView):
    """
    用户认证获取token
    """

    permission_classes = []

    def post(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')
        # data = json.loads(request.body.decode('utf-8'))
        user = UserProfileModel.objects.filter(Q(username=username) | Q(mobile=username)).first()
        if user:
            if user.check_password(password):
                if user.is_active or user.is_superuser:
                    if user.roles.all():
                        payload = jwt_payload_handler(user)
                        data = {'token': jwt.encode(payload, SECRET_KEY)}
                        landing(request, username, 200, '-')
                        return JsonResponse(data=data, code=200, message='登陆成功', status=status.HTTP_200_OK)
                    else:
                        landing(request, username, 401, '用户无系统角色，请联系管理员授予')
                        return JsonResponse(data={}, code=401, message='用户无系统角色，请联系管理员授予', status=status.HTTP_400_BAD_REQUEST)
                else:
                    landing(request, username, 403, '用户无登陆权')
                    return JsonResponse(data={}, code=403, message='用户无登陆权', status=status.HTTP_400_BAD_REQUEST)
            else:
                landing(request, username, 400, '用户密码不正确')
                return JsonResponse(data={}, code=400, message='用户密码不正确', status=status.HTTP_400_BAD_REQUEST)
        else:
            landing(request, username, 400, '用户不存在')
            return JsonResponse(data={}, code=400, message='用户不存在', status=status.HTTP_400_BAD_REQUEST)


class UserInfoView(APIView):
    """
    获取当前用户信息和权限
    """

    @classmethod
    def get_permission_from_role(self, request):
        try:
            if request.user:
                perms_list = []
                for item in request.user.roles.values('permissions__method').distinct():
                    perms_list.append(item['permissions__method'])
                return perms_list
        except AttributeError:
            return None

    def get(self, request):
        if request.user.id is not None:
            perms = self.get_permission_from_role(request)
            data = {
                'id': request.user.id,
                'name': request.user.name,
                'username': request.user.username,
                'avatar': request.user.avatar,
                'email': request.user.email,
                'is_active': request.user.is_active,
                'createTime': request.user.date_joined,
                'roles': perms
            }
            return JsonResponse(data=data, code=200, status=status.HTTP_200_OK)
        else:
            return JsonResponse(message='请登录后访问!', code=400, status=status.HTTP_400_BAD_REQUEST)


class UserBuildMenuView(APIView):
    """
    绑定当前用户菜单信息
    """

    def get_menu_from_role(self, request):
        if request.user:
            menu_dict = {}
            menus = request.user.roles.values(
                'menus__id',
                'menus__name',
                'menus__path',
                'menus__is_frame',
                'menus__is_show',
                'menus__component',
                'menus__icon',
                'menus__sort',
                'menus__pid'
            ).distinct()
            for item in menus:
                if item['menus__pid'] is None:
                    if item['menus__is_frame']:
                        # 判断是否外部链接
                        top_menu = {
                            'id': item['menus__id'],
                            'path': item['menus__path'],
                            'component': 'Layout',
                            'children': [{
                                'path': item['menus__path'],
                                'meta': {
                                    'title': item['menus__name'],
                                    'icon': item['menus__icon']
                                }
                            }],
                            'pid': item['menus__pid'],
                            'sort': item['menus__sort']
                        }
                    else:
                        top_menu = {
                            'id': item['menus__id'],
                            'name': item['menus__name'],
                            'path': '/' + str(item['menus__path']),
                            'redirect': 'noRedirect',
                            'component': 'Layout',
                            'alwaysShow': True,
                            'meta': {
                                'title': item['menus__name'],
                                'icon': item['menus__icon']
                            },
                            'pid': item['menus__pid'],
                            'sort': item['menus__sort'],
                            'children': []
                        }
                    menu_dict[item['menus__id']] = top_menu
                else:
                    if item['menus__is_frame']:
                        children_menu = {
                            'id': item['menus__id'],
                            'name': item['menus__name'],
                            'path': item['menus__path'],
                            'component': 'Layout',
                            'meta': {
                                'title': item['menus__name'],
                                'icon': item['menus__icon'],
                            },
                            'pid': item['menus__pid'],
                            'sort': item['menus__sort']
                        }
                    elif item['menus__is_show']:
                        children_menu = {
                            'id': item['menus__id'],
                            'name': item['menus__name'],
                            'path': item['menus__path'],
                            'component': item['menus__component'],
                            'meta': {
                                'title': item['menus__name'],
                                'icon': item['menus__icon'],
                            },
                            'pid': item['menus__pid'],
                            'sort': item['menus__sort']
                        }
                    else:
                        children_menu = {
                            'id': item['menus__id'],
                            'name': item['menus__name'],
                            'path': item['menus__path'],
                            'component': item['menus__component'],
                            'meta': {
                                'title': item['menus__name'],
                                'noCache': True,
                            },
                            'hidden': True,
                            'pid': item['menus__pid'],
                            'sort': item['menus__sort']
                        }
                    menu_dict[item['menus__id']] = children_menu
            return menu_dict

    def get_all_menu_dict(self):
        """
        获取所有菜单数据，重组结构
        :return:
        """
        menus = Menu.objects.all()
        serializer = menu.MenuSerializer(menus, many=True)
        tree_dict = {}
        for item in serializer.data:
            if item['pid'] is None:
                if item['is_frame']:
                    # 判断是否外部链接
                    top_menu = {
                        'id': item['id'],
                        'path': item['path'],
                        'component': 'Layout',
                        'children': [{
                            'path': item['path'],
                            'meta': {
                                'title': item['name'],
                                'icon': item['icon']
                            }
                        }],
                        'pid': item['pid'],
                        'sort': item['sort']
                    }
                else:
                    top_menu = {
                        'id': item['id'],
                        'name': item['name'],
                        'path': '/' + item['path'],
                        'redirect': 'noRedirect',
                        'component': 'Layout',
                        'alwaysShow': True,
                        'meta': {
                            'title': item['name'],
                            'icon': item['icon']
                        },
                        'pid': item['pid'],
                        'sort': item['sort'],
                        'children': []
                    }
                tree_dict[item['id']] = top_menu
            else:
                if item['is_frame']:
                    children_menu = {
                        'id': item['id'],
                        'name': item['name'],
                        'path': item['path'],
                        'component': 'Layout',
                        'meta': {
                            'title': item['name'],
                            'icon': item['icon'],
                        },
                        'pid': item['pid'],
                        'sort': item['sort']
                    }
                elif item['is_show']:
                    children_menu = {
                        'id': item['id'],
                        'name': item['name'],
                        'path': item['path'],
                        'component': item['component'],
                        'meta': {
                            'title': item['name'],
                            'icon': item['icon'],
                        },
                        'pid': item['pid'],
                        'sort': item['sort']
                    }
                else:
                    children_menu = {
                        'id': item['id'],
                        'name': item['name'],
                        'path': item['path'],
                        'component': item['component'],
                        'meta': {
                            'title': item['name'],
                            'noCache': True,
                        },
                        'hidden': True,
                        'pid': item['pid'],
                        'sort': item['sort']
                    }
                tree_dict[item['id']] = children_menu
        return tree_dict

    def get_all_menus(self, request):
        perms = UserInfoView.get_permission_from_role(request)
        tree_data = []
        if 'admin' in perms or request.user.is_superuser:
            tree_dict = self.get_all_menu_dict()
        else:
            tree_dict = self.get_menu_from_role(request)
        for i in tree_dict:
            if tree_dict[i]['pid']:
                pid = tree_dict[i]['pid']
                parent = tree_dict[pid]
                parent.setdefault('redirect', 'noRedirect')
                parent.setdefault('alwaysShow', True)
                parent.setdefault('children', []).append(tree_dict[i])
                parent['children'] = sorted(parent['children'], key=itemgetter('sort'))
            else:
                tree_data.append(tree_dict[i])
        return tree_data

    def get(self, request):
        menu_data = self.get_all_menus(request)
        return JsonResponse(data=menu_data, code=200, message='成功', status=status.HTTP_200_OK)


class UserProfileModelView(CustomModelViewSet):
    """
    用户管理：增删改查导
    """
    perms_map = ({'*': 'admin'}, {'*': 'user_all'}, {'get': 'user_list'}, {'post': 'user_create'}, {'put': 'user_edit'},
                 {'delete': 'user_delete'}, {'export': 'user_export'})
    queryset = UserProfileModel.objects.all().exclude(username='admin')
    serializer_class = user.UserProfileModelListSerializer
    filter_fields = ('is_active',)
    search_fields = ('username', 'name', 'mobile', 'email', 'department__name', 'position')  # 已在全局设置：指定字段模糊搜索
    ordering_fields = ('date_joined',)  # 已在全局设置：指定字段排序

    sheet = '用户表'
    title = {
        'id': 'ID', 'username': '用户名', 'name': '姓名', 'mobile': '手机号码', 'email': '邮箱地址',
        'department': '所属部门', 'position': '职位名称', 'is_active': '账户状态', 'roles': '角色权限',
        'superior': '上级主管', 'date_joined': '加入时间', 'introduction': '描述说明'
    }

    def get_serializer_class(self):
        # 根据请求类型动态变更serializer
        if self.action == 'create':
            return user.UserProfileModelCreateSerializer
        elif self.action == 'list':
            return user.UserProfileModelListSerializer
        elif self.action == 'retrieve':
            return user.UserProfileModelRetrieveViewSerializer
        elif self.action == 'export_current' or self.action == 'export_all':
            return user.UserProfileModelExportSerializer
        return user.UserProfileModelUpdateSerializer

    def create(self, request, *args, **kwargs):
        """
        创建一个模型实例.
        """
        request.data['password'] = make_password('123456')
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        operation.operation(request, serializer.data['name'], serializer.instance._meta.verbose_name_plural, '创建')
        headers = self.get_success_headers(serializer.data)
        return JsonResponse(data=serializer.data, code=200,
                            message="新增【 " + serializer.data['username'] + " 】用户.",
                            status=status.HTTP_200_OK,
                            headers=headers)

    def update(self, request, *args, **kwargs):
        """
        更新模型实例.
        """
        if request.data['username'] not in request.user.username:
            partial = kwargs.pop('partial', False)
            instance = self.get_object()
            serializer = self.get_serializer(instance, data=request.data, partial=partial)
            serializer.is_valid(raise_exception=True)
            self.perform_update(serializer)

            if getattr(instance, '_prefetched_objects_cache', None):
                # 如果'prefetch_related'已经应用到queryset，需要强制取消实例上的预取缓存
                instance._prefetched_objects_cache = {}
            operation.operation(request, instance, instance._meta.verbose_name_plural, '更新')
            return JsonResponse(data=serializer.data, code=200, message="成功", status=status.HTTP_200_OK)
        else:
            return JsonResponse(data={}, code=400, message="禁止修改当前已登陆用户信息", status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'], detail=True)  # url 访问127.0.0.1:8080/api/<pk>/方法名
    def reset_password(self, request, pk):
        """
        重置密码: 123456
        """
        perms = UserInfoView.get_permission_from_role(request)
        if 'admin' in perms or 'user_all' in perms or request.user.is_superuser:
            user = UserProfileModel.objects.filter(id=pk).first()
            if user.username not in request.user.username:
                user.password = make_password('123456')
                user.save()
                operation.operation(request, user.username + '(' + user.name + ')', '用户管理', '重置密码')
                return JsonResponse(data={}, code=200, message='重置用户密码', status=status.HTTP_200_OK)
            else:
                return JsonResponse(data={}, code=400, message="您已登陆，无法重置密码，请前往【个人中心】修改密码", status=status.HTTP_400_BAD_REQUEST)
        else:
            return JsonResponse(data={}, code=400, message='您越权了', status=status.HTTP_400_BAD_REQUEST)

    def destroy(self, request, *args, **kwargs):
        """
        删除一个模型实例.
        """
        instance = self.get_object()
        if instance.username not in request.user.username:
            self.perform_destroy(instance)
            operation.operation(request, instance, instance._meta.verbose_name_plural, '删除')
            return JsonResponse(data=[], code=200, message="成功", status=status.HTTP_200_OK)
        else:
            return JsonResponse(data={}, code=400, message="您无法删除自己，请使用其它有权限账户来操作，请刷新", status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'], detail=True)  # url 访问127.0.0.1:8080/api/<pk>/方法名
    def update_password(self, request, pk):
        """
        个人中心 - 密码修改
        """
        data = request.data
        user = UserProfileModel.objects.filter(id=pk).first()
        if int(pk) == request.user.id:
            if check_password(data['old_password'], user.password):
                if data['new_password1'] == data['new_password2']:
                    user.set_password(data['new_password2'])
                    user.save()
                    return JsonResponse(data={}, code=200, message='密码修改', status=status.HTTP_200_OK)
                else:
                    return JsonResponse(data={}, code=400, message='新密码两次输入不一致', status=status.HTTP_400_BAD_REQUEST)
            else:
                return JsonResponse(data={}, code=400, message='旧密码错误', status=status.HTTP_400_BAD_REQUEST)
        else:
            return JsonResponse(data={}, code=400, message='这不是你的账户', status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'], detail=True)  # url 访问127.0.0.1:8080/api/<pk>/方法名
    def update_image(self, request, pk):
        """
        个人中心 - 头像修改
        """
        data = request.data
        try:
            if int(pk) == request.user.id:
                user = UserProfileModel.objects.filter(id=pk).first()
                user.avatar = data['name']
                user.save()
                return JsonResponse(data={'name': data['name']}, code=200, message='头像修改', status=status.HTTP_200_OK)
            else:
                return JsonResponse(data={}, code=400, message='这不是您的账户', status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            return JsonResponse(data={}, code=400, message='头像修改错误：' + str(e), status=status.HTTP_400_BAD_REQUEST)
